/* 
 * File:   randomtestadventurer.c
 * Author: Arnold Baghomian
 * Class: CS362
 * Assignment 4
 *
 * Created on July 22, 2014, 12:49 PM
 */
#define _GNU_SOURCE
#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "rngs.h"
#include <math.h>
//define DUMP 
int count = 0;

int countCopper(int ahand[], int size_hand) {
    int i, card, count = 0;
    for (i = 0; i < size_hand; ++i) {
        card = ahand[i];
        if (card == copper)
            count++;
    }
}

int countSilver(int ahand[], int size_hand) {
    int i, card, count = 0;
    for (i = 0; i < size_hand; ++i) {
        card = ahand[i];
        if (card == silver)
            count++;
    }
}

int countGold(int ahand[], int size_hand) {
    int i, card, count = 0;
    for (i = 0; i < size_hand; ++i) {
        card = ahand[i];
        if (card == gold)
            count++;
    }
}

int countTreasureCards(int ahand[], int size_hand) {
    int i, card, count = 0;
    for (i = 0; i < size_hand; ++i) {
        card = ahand[i];
        if (card == silver || card == copper || card == gold)
            count++;
    }
    return count;
}

void dumpState(FILE* fp, struct gameState *g, char* s) {
    int i, j;
    fprintf(fp, "\n");
    fprintf(fp, "%s\n", s);
    fprintf(fp, "dump of game state:\n");
    fprintf(fp, "\n");
    fprintf(fp, "number of players %d\n", g->numPlayers);
    fprintf(fp, "       whose turn %d\n", g->whoseTurn);
    fprintf(fp, "            coins %d\n", g->coins);
    fprintf(fp, "number of actions %d\n", g->numActions);
    fprintf(fp, "   number of buys %d\n", g->numBuys);
    fprintf(fp, "   outpost played %d\n", g->outpostPlayed);
    fprintf(fp, "     outpost turn %d\n", g->outpostTurn);
    fprintf(fp, "            phase %d\n", g->phase);
    fprintf(fp, "played card count %d\n", g->playedCardCount);
    //fprintf(fp,"\n");
    fprintf(fp, "\nsupply count: ");
    for (i = 0; i < treasure_map + 1; ++i)
        //fprintf(fp,"     supply count[%d] = %d\n",  i, (g->supplyCount[i]));  
        fprintf(fp, "%d, ", (g->supplyCount[i]));

    fprintf(fp, "\n");
    fprintf(fp, "\nembargo tokens: ");
    for (i = 0; i < treasure_map + 1; ++i)
        //fprintf(fp,"    embargo tokens[%d] = %d\n", i, (g->embargoTokens[i]));  
        fprintf(fp, "%d, ", (g->embargoTokens[i]));
    fprintf(fp, "\n");
    fprintf(fp, "\nplayed card: ");
    for (j = 0; j < g->playedCardCount; j++)
        //fprintf(fp,"    played card[%d] = %d\n", j, (g->playedCards[j]));    
        fprintf(fp, "%d, ", (g->playedCards[j]));


    for (i = 0; i < g->numPlayers; ++i) {
        fprintf(fp, "\nPlayer %d\n", i);
        fprintf(fp, "   handcount %d\n", g->handCount[i]);
        fprintf(fp, "   deckcount %d\n", g->deckCount[i]);
        fprintf(fp, "discardcount %d\n", g->discardCount[i]);
        fprintf(fp, "\nhand: ");
        for (j = 0; j < g->handCount[i]; j++)
            //fprintf(fp,"           hand[%d] = %d\n", j, g->hand[i][j]);    
            fprintf(fp, "%d, ", g->hand[i][j]);
        fprintf(fp, "\ndeck: ");
        for (j = 0; j < g->deckCount[i]; j++)
            //fprintf(fp,"           deck[%d] = %d\n", j, g->deck[i][j]);    
            fprintf(fp, "%d, ", g->deck[i][j]);
        fprintf(fp, "\ndiscard: ");
        for (j = 0; j < g->discardCount[i]; j++)
            //fprintf(fp,"        discard[%d] = %d\n", j, g->discard[i][j]);                
            fprintf(fp, "%d, ", g->discard[i][j]);
    }
    fprintf(fp, "\nEnd of dump\n");
    fflush(fp);
}



//void zzzadventurercardplay(int drawntreasure, int currentPlayer, int cardDrawn,
//		int temphand[MAX_HAND], int z, struct gameState* state) {

int zzzadventurertest(int iter, int p, int handPos, struct gameState *g, FILE* fp) {
    int i; //for loops
    int pass = 1; // did this test pass = 1, fail = 0
    int numDiscards;
    int numP = g->numPlayers;
    assert(numP > 0 && numP < 5); // check number of players
    struct gameState preState;
    struct gameState *pre = &preState;
    memcpy(pre, g, sizeof (struct gameState)); // copy the games state before for comparison
#ifdef DUMP
    dumpState(fp, pre, "   before call\n");
#endif    
    int temphand[MAX_HAND]; // moved above the if statement
    int drawntreasure = 0;
    int emulatedtreasuredrawn = 0;
    int coppercount = 0;
    int silvercount = 0;
    int goldcount = 0;

    int cardDrawn, acard, treasurecardcount = 0;
    int z = 0; // this is the counter for the temp hand
    // call tested function
    zzzadventurercardplay(drawntreasure, p, cardDrawn,
            temphand, z, g);

    int noshuffle = 1; // no need to shuffle
    int new_discards = 0;
    // count number of treasure cards in hand
    for (i = pre->deckCount[p] - 1; i >= 0; --i) {

        acard = pre->deck[p][i];
        if (acard == copper) {
            treasurecardcount++;
            coppercount++;
            emulatedtreasuredrawn += 1;
        } else if (acard == silver) {
            treasurecardcount++;
            silvercount++;
            emulatedtreasuredrawn += 2;
        } else if (acard == gold) {
            treasurecardcount++;
            goldcount++;
            emulatedtreasuredrawn += 3;

        } else
            new_discards++; // this card will be discard

        if (treasurecardcount > 1) break; //only need 2 cards

    }
    int original_treasure_discardcard_count = countTreasureCards(pre->discard[p], pre->discardCount[p]);
    noshuffle == treasurecardcount > 1; //otherwise we will shuffle

    //check for total treasure cards
    int original_treasure_card_count = countTreasureCards(pre->hand[p], pre->handCount[p]);
    int final_treasure_card_count = countTreasureCards(g->hand[p], g->handCount[p]);
    int original_treasure_deck_count = countTreasureCards(pre->deck[p], pre->deckCount[p]);
    if ((treasurecardcount + original_treasure_discardcard_count > 1) && (final_treasure_card_count - original_treasure_card_count) == 2) {
        pass = 1;
    } else if ((treasurecardcount + original_treasure_discardcard_count == 1) && (final_treasure_card_count - original_treasure_card_count) == 1) {
        pass = 1;
    } else if ((treasurecardcount + original_treasure_discardcard_count == 0) && (final_treasure_card_count - original_treasure_card_count) == 0) {
        pass = 1;
    } else
        pass = 0;

    // check for cards we know should be in hand
    if (coppercount == countCopper(g->hand[p], g->handCount[p]) - countCopper(pre->hand[p], pre->handCount[p]))
        pass = pass * 1;
    if (silvercount == countSilver(g->hand[p], g->handCount[p]) - countSilver(pre->hand[p], pre->handCount[p]))
        pass = pass * 1;
    if (goldcount == countGold(g->hand[p], g->handCount[p]) - countGold(pre->hand[p], pre->handCount[p]))
        pass = pass * 1;

    //check for shuffle
    int final_treasure_discardcard_count = countTreasureCards(g->discard[p], g->discardCount[p]);
    int final_treasure_deck_count = countTreasureCards(g->deck[p], g->deckCount[p]);
    if (original_treasure_deck_count > 1 && noshuffle == 0) pass = 0; //should not have shuffled
    //    //didn't shuffle so discards should have same treasure count
    if (noshuffle == 1)
        pass = pass && (original_treasure_discardcard_count == final_treasure_discardcard_count);

    if (noshuffle == 0 && pass == 1) {
        //if the cards had to be shuffled there can be no treasure cards in discard pile
        if (final_treasure_discardcard_count == 0) pass = 1;
        else pass = 0;

        //the deck should have all the treasure cards from the discards except what needed for hand
        if ((treasurecardcount + original_treasure_discardcard_count > 1)) // if there were enough treasure cards and we shuffled
            if (final_treasure_deck_count - original_treasure_deck_count == original_treasure_discardcard_count - (2 - treasurecardcount)) pass = pass * 1;
        if ((treasurecardcount + original_treasure_discardcard_count == 1)) // if there was only 1 treasure card and we shuffled
        {
            // only one card was found
            if (treasurecardcount == 0) pass = pass && original_treasure_discardcard_count == 1;
            if (treasurecardcount == 1) pass = pass && original_treasure_discardcard_count == 0;
        }

    }

    if (!pass) {
        count++;
        printf("Iteration %d assert failed.\n", iter);
    }

    return pass;

}



struct gameState G;

int main() {

    int i, j, n, r, p, deckCount, discardCount, handCount, players, handPos;

    int k[10] = {adventurer, council_room, feast, gardens, mine,
        remodel, smithy, village, baron, great_hall};

    FILE * fp;

#ifdef DUMP
    fp = fopen("randomtestcard.log", "w");
#endif
    printf("Testing adventurer card.\n");

    printf("RANDOM TESTS.\n");

    SelectStream(2);
    //PutSeed(3);
    PutSeed(5);
    int trials = 2000;
    for (n = 0; n < trials; n++) {
        //printf("test iteration %d\n", (n+1));
        // for (i = 0; i < sizeof (struct gameState); i++) {
        //     ((int*) &G)[i] = (char)floor(Random() * 1024);  // everything in the game is a small integer
        // }
        for (j = 0; j < MAX_DECK; j++) {
            G.playedCards[j] = floor(Random() * (treasure_map + 1));
        }
        for (i = 0; i < MAX_PLAYERS; i++) {
            for (j = 0; j < MAX_HAND; j++)
                G.hand[i][j] = floor(Random() * (treasure_map + 1));
            for (j = 0; j < MAX_DECK; j++) {
                G.deck[i][j] = floor(Random() * (treasure_map + 1));
                G.discard[i][j] = floor(Random() * (treasure_map + 1));
            }
        }
        for (i = 0; i < treasure_map + 1; i++) {
            G.supplyCount[i] = floor(Random()*100);
            G.embargoTokens[i] = floor(Random()*100);
        }
        players = floor(Random()* 3) + 2; // 2 - 4 payers allowed
        G.numPlayers = players;
        //set random deck sizes for each player
        for (i = 0; i < players; ++i) {
            G.deckCount[i] = floor(Random() * MAX_DECK);
            G.discardCount[i] = floor(Random() * MAX_DECK);
            G.handCount[i] = floor(Random() * MAX_HAND);
        }

        p = floor(Random() * players); // pick a random player
        handPos = floor(Random() * G.handCount[p]); // pick a random card in hand
        G.whoseTurn = p;
        G.coins = floor(Random()*200);
        G.numActions = floor(Random()*100);
        G.numBuys = floor(Random()*100);
        G.outpostPlayed = floor(Random()*100);
        G.outpostTurn = floor(Random()*100); // not used in code
        G.phase = floor(Random()*2); // not used in code
        G.playedCardCount = floor(Random()*100);



        G.hand[p][handPos] = adventurer; // set card to council room
        zzzadventurertest(n, p, handPos, &G, fp);

    }

    printf("\nTotal trials %d, total failed %d\n", trials, count);
#ifdef DUMP
    fclose(fp);
#endif
    return 0;

}